package com.yipei.business.service.impl;

import cn.hutool.core.convert.NumberChineseFormatter;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.yipei.business.domain.MlKLineMaster;
import com.yipei.business.mapper.MlKLineMasterMapper;
import com.yipei.business.service.IMlKLineMasterService;
import com.yipei.business.vo.*;
import com.yipei.common.utils.DateUtils;
import com.yipei.common.utils.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.poi.hssf.record.chart.TickRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.time.Duration;
import java.time.LocalTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 行情Service业务层处理
 *
 * @author yipei
 * @date 2024-12-20
 */
@Service
public class MlKLineMasterServiceImpl implements IMlKLineMasterService {
    @Autowired
    private MlKLineMasterMapper mlKLineMasterMapper;

    /**
     * 查询行情
     *
     * @param id 行情主键
     * @return 行情
     */
    @Override
    public MlKLineMaster selectMlKLineMasterById(Long id) {
        return mlKLineMasterMapper.selectMlKLineMasterById(id);
    }

    /**
     * 查询行情列表
     *
     * @param mlKLineMaster 行情
     * @return 行情
     */
    @Override
    public List<MlKLineMaster> selectMlKLineMasterList(MlKLineMaster mlKLineMaster) {
        return mlKLineMasterMapper.selectMlKLineMasterList(mlKLineMaster);
    }

    /**
     * 新增行情
     *
     * @param mlKLineMaster 行情
     * @return 结果
     */
    @Override
    public int insertMlKLineMaster(MlKLineMaster mlKLineMaster) {
        mlKLineMaster.setCreateTime(DateUtils.getNowDate());
        return mlKLineMasterMapper.insertMlKLineMaster(mlKLineMaster);
    }

    /**
     * 修改行情
     *
     * @param mlKLineMaster 行情
     * @return 结果
     */
    @Override
    public int updateMlKLineMaster(MlKLineMaster mlKLineMaster) {
        mlKLineMaster.setUpdateTime(DateUtils.getNowDate());
        return mlKLineMasterMapper.updateMlKLineMaster(mlKLineMaster);
    }

    /**
     * 批量删除行情
     *
     * @param ids 需要删除的行情主键
     * @return 结果
     */
    @Override
    public int deleteMlKLineMasterByIds(Long[] ids) {
        return mlKLineMasterMapper.deleteMlKLineMasterByIds(ids);
    }

    /**
     * 删除行情信息
     *
     * @param id 行情主键
     * @return 结果
     */
    @Override
    public int deleteMlKLineMasterById(Long id) {
        return mlKLineMasterMapper.deleteMlKLineMasterById(id);
    }

    @Override
    public List<MlKLineMasterVo> getSymbolInfo(String f12, String f14) throws IOException, InterruptedException {
        // https://push2.eastmoney.com/api/qt/ulist.np/get?ut=6d2ffaa6a585d612eda28417681d58fb&secids=0.516060,1.516060&cb=jQuery
        HttpClient client = HttpClients.createDefault();
//        HttpGet request = new HttpGet("https://push2.eastmoney.com/api/qt/ulist.np/get?ut=6d2ffaa6a585d612eda28417681d58fb&secids=0." + f12 + ",1." + f12 + "&cb=jQuery"); //示例URL，请替换为实际的股票代码
        String symbol = "sh" + f12 + ",sz" + f12 + ",bj" + f12;
        HttpGet request = new HttpGet("https://sqt.gtimg.cn/?q=" + symbol + "&fmt=json&app=wstock&t=" + System.currentTimeMillis()); //
        List<MlKLineMasterVo> ajaxResult = this.getAjaxResult(client, request);
        if (StringUtils.isNotEmpty(f14)){
            ajaxResult=ajaxResult.stream().filter(e->e.getF14().equals(f14)).collect(Collectors.toList());
        }
        HttpClient client2 = HttpClients.createDefault();
        HttpGet request2 = new HttpGet("https://finance.pae.baidu.com/vapi/v1/getquotation?srcid=5353&all=1&code=" + f12 + "&query=" + f12 + "&eprop=min&stock_type=ab&chartType=minute&group=quotation_minute_ab&finClientType=pc"); //示例URL，请替换为实际的股票代码
        request.setHeader("Content-Type", "text/javascript;charset=UTF-8");
        HttpResponse response2 = client2.execute(request2);
        List<PankouinfosVo> todayDaealVos = new ArrayList<>();
        if (response2.getStatusLine().getStatusCode() == 200) {
            HttpEntity entity = response2.getEntity();
            String result = EntityUtils.toString(entity, "UTF-8").replace("jQuery", "");
            JSONObject jsonObject = JSONObject.parseObject(result).getJSONObject("Result");
            JSONArray details = jsonObject.getJSONObject("pankouinfos").getJSONArray("list");
            todayDaealVos = details.toJavaList(PankouinfosVo.class);
            for (MlKLineMasterVo mlKLineMasterVo : ajaxResult) {
                for (PankouinfosVo todayDaealVo : todayDaealVos) {
//                    if (todayDaealVo.getEname().equals("limitDown")) {
//                        mlKLineMasterVo.setLower_limit(todayDaealVo.getValue());
//                    }
//                    if (todayDaealVo.getEname().equals("limitUp")) {
//                        mlKLineMasterVo.setUpper_limit(todayDaealVo.getValue());
//                    }
                    if (todayDaealVo.getEname().equals("totalShareCapital")) {
                        mlKLineMasterVo.setZgb(todayDaealVo.getValue());
                    }
                    if (todayDaealVo.getEname().equals("circulatingCapital")) {
                        mlKLineMasterVo.setLt_gb(todayDaealVo.getValue());
                    }
                }
            }
        }
        return ajaxResult;
    }

    @Override
    public List<MlKLineMasterVo> getAguMklines(List<String> codes) throws IOException, InterruptedException {
        List<MlKLineMasterVo> mlKLineMasterVos = new ArrayList<>();
        int batchSize = 500;
        for (int i = 0; i < codes.size(); i += batchSize) {
            List<String> batch = codes.subList(i, Math.min(i + batchSize, codes.size()));
            String query = URLEncoder.encode(String.join(",", batch), "UTF-8");
            HttpClient client = HttpClients.createDefault();
            HttpGet request = new HttpGet("https://sqt.gtimg.cn/?q=" + query + "&fmt=json&app=wstock&t=" + System.currentTimeMillis());
            List<MlKLineMasterVo> ajaxResult = this.getAjaxResultSout(client, request);
            mlKLineMasterVos.addAll(ajaxResult);
        }
        return mlKLineMasterVos;
    }

    private List<MlKLineMasterVo> getAjaxResultSout(HttpClient client, HttpGet request) throws InterruptedException, IOException {
        request.setHeader("Content-Type", "text/javascript;charset=UTF-8");
        HttpResponse response = client.execute(request);
        List<MlKLineMasterVo> mlKLineMasters = new ArrayList<>();
        if (response.getStatusLine().getStatusCode() == 200) {
            HttpEntity entity = response.getEntity();
            String json = EntityUtils.toString(entity, "UTF-8").replace("jQuery", "");
            Gson gson = new Gson();
            JsonObject obj = gson.fromJson(json, JsonObject.class);
            for (String code : obj.keySet()) {
                JsonArray arr = obj.getAsJsonArray(code);
                MlKLineMasterVo mlKLineMasterVo = new MlKLineMasterVo();
                mlKLineMasterVo.setF2(arr.get(3).getAsString());
                mlKLineMasterVo.setF3(arr.get(32).getAsString()+"%");
                mlKLineMasterVo.setF4(arr.get(31).getAsString()+"%");
                mlKLineMasterVo.setF5(arr.get(6).getAsString());
                mlKLineMasterVo.setF6(String.valueOf(new BigDecimal(mlKLineMasterVo.getF2()).multiply(new BigDecimal(mlKLineMasterVo.getF5())).multiply(new BigDecimal(100))));
                mlKLineMasterVo.setF7(arr.get(42).getAsString()+"%");
                mlKLineMasterVo.setF8(arr.get(38).getAsString()+"%");
                if (StringUtils.isNotEmpty(arr.get(52).getAsString())){
                    mlKLineMasterVo.setF9(String.valueOf(arr.get(52).getAsBigDecimal().multiply(new BigDecimal(100))));
                }
                mlKLineMasterVo.setF15(arr.get(33).getAsString());
                mlKLineMasterVo.setF16(arr.get(34).getAsString());
                mlKLineMasterVo.setF17(arr.get(5).getAsString());
                mlKLineMasterVo.setF18(arr.get(4).getAsString());
                mlKLineMasterVo.setF12(arr.get(2).getAsString());
                mlKLineMasterVo.setF14(arr.get(1).getAsString());
                mlKLineMasterVo.setF23(String.valueOf(new BigDecimal(arr.get(46).getAsString()).multiply(new BigDecimal(100))));
                mlKLineMasterVo.setSymbol(arr.get(2).getAsString());
                mlKLineMasterVo.setUpper_limit(arr.get(47).getAsString());
                mlKLineMasterVo.setLower_limit(arr.get(48).getAsString());
                mlKLineMasters.add(mlKLineMasterVo);
            }
            // 防止频繁请求被风控
            Thread.sleep(600);
        }
        return mlKLineMasters;
    }

    @Override
    public List<MlKLineMasterVo> getIndexData(HttpClient client, HttpGet request) throws IOException, InterruptedException {
        List<MlKLineMasterVo> mlKLineMasterVos = this.getAjaxResult(client, request);
        return mlKLineMasterVos;
    }

    @Override
    public List<MlKLineMasterVo> getKeChuangData(HttpClient client, HttpGet request) throws IOException, InterruptedException {
        List<MlKLineMasterVo> mlKLineMasterVos = this.getAjaxResult(client, request);
        return mlKLineMasterVos;
    }

    @Override
    public List<MlKLineMasterVo> getChuangYeBan(HttpClient client, HttpGet request) throws IOException, InterruptedException {
        List<MlKLineMasterVo> mlKLineMasterVos = this.getAjaxResult(client, request);
        return mlKLineMasterVos;
    }

    @Override
    public List<TodayDaealVo> fetchLatestTicks(String stockCode, int limit) {
        PriorityQueue<TodayDaealVo> maxHeap = new PriorityQueue<>(limit, Comparator.comparingLong(TodayDaealVo::getTimeDiff).reversed());
        int page = 0;
        LocalTime now = LocalTime.now();

        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(3000)
                .setSocketTimeout(3000)
                .build();

        try (CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(requestConfig).build()) {
            boolean hasMore = true;

            while (hasMore) {
                String url = String.format("https://stock.gtimg.cn/data/index.php?appn=detail&action=data&c=%s&p=%d", stockCode, page);
                HttpGet get = new HttpGet(url);
                String raw = EntityUtils.toString(client.execute(get).getEntity(), Charset.forName("GBK"));

                // ✅ 替代正则，更快
                int start = raw.indexOf("v_detail_data_" + stockCode + "=[");
                if (start == -1) break;

                int arrayStart = raw.indexOf("[", start);
                int arrayEnd = raw.lastIndexOf("]");
                if (arrayStart == -1 || arrayEnd == -1 || arrayEnd <= arrayStart) break;

                String jsonArrayStr = raw.substring(arrayStart, arrayEnd + 1);
                JSONArray array = JSON.parseArray(jsonArrayStr);
                if (array.size() < 2) break;

                String tickDataStr = array.getString(1);
                if (tickDataStr == null || tickDataStr.isEmpty()) break;

                String[] records = tickDataStr.split("\\|");

                boolean pageHasCloserData = false;
                for (String record : records) {
                    String[] fields = record.split("/");
                    if (fields.length >= 7) {
                        String timeStr = fields[1];
                        LocalTime tickTime;
                        try {
                            tickTime = LocalTime.parse(timeStr);
                        } catch (Exception e) {
                            continue;
                        }

                        long diff = Math.abs(Duration.between(now, tickTime).toMillis());

                        TodayDaealVo tick = new TodayDaealVo();
                        tick.setFormatTime(timeStr);
                        tick.setPrice(new BigDecimal(fields[2]));
                        tick.setVolume(new BigDecimal(fields[4]).multiply(BigDecimal.valueOf(100)));
                        tick.setBsFlag(fields[6]);
                        tick.setTimeDiff(diff);

                        if (maxHeap.size() < limit) {
                            maxHeap.offer(tick);
                            pageHasCloserData = true;
                        } else if (diff < maxHeap.peek().getTimeDiff()) {
                            maxHeap.poll(); // 移除最远
                            maxHeap.offer(tick);
                            pageHasCloserData = true;
                        }
                    }
                }

                if (!pageHasCloserData) break;

                page++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 返回排序后的结果
        List<TodayDaealVo> result = new ArrayList<>(maxHeap);
        result.sort(Comparator.comparingLong(TodayDaealVo::getTimeDiff)); // 可省略，若不需要有序
        return result;
    }


    private List<MlKLineMasterVo> getAjaxResult(HttpClient client, HttpGet request) throws IOException, InterruptedException {
        request.setHeader("Content-Type", "text/javascript;charset=UTF-8");
        HttpResponse response = client.execute(request);
        List<MlKLineMasterVo> mlKLineMasters = new ArrayList<>();
        if (response.getStatusLine().getStatusCode() == 200) {
            HttpEntity entity = response.getEntity();
            String json = EntityUtils.toString(entity, "UTF-8").replace("jQuery", "");
            Gson gson = new Gson();
            JsonObject obj = gson.fromJson(json, JsonObject.class);
            for (String code : obj.keySet()) {
                JsonArray arr = obj.getAsJsonArray(code);
                MlKLineMasterVo mlKLineMasterVo = new MlKLineMasterVo();
                mlKLineMasterVo.setF2(arr.get(3).getAsString());
                mlKLineMasterVo.setF3(arr.get(32).getAsString()+"%");
                mlKLineMasterVo.setF4(arr.get(31).getAsString()+"%");
                mlKLineMasterVo.setF5(arr.get(6).getAsString());
                mlKLineMasterVo.setF6(String.valueOf(new BigDecimal(mlKLineMasterVo.getF2()).multiply(new BigDecimal(mlKLineMasterVo.getF5())).multiply(new BigDecimal(100))));
                mlKLineMasterVo.setF7(arr.get(42).getAsString()+"%");
                mlKLineMasterVo.setF8(arr.get(38).getAsString()+"%");
                if (StringUtils.isNotEmpty(arr.get(52).getAsString())){
                    mlKLineMasterVo.setF9(String.valueOf(arr.get(52).getAsBigDecimal().multiply(new BigDecimal(100))));
                }
                mlKLineMasterVo.setF15(arr.get(33).getAsString());
                mlKLineMasterVo.setF16(arr.get(34).getAsString());
                mlKLineMasterVo.setF17(arr.get(5).getAsString());
                mlKLineMasterVo.setF18(arr.get(4).getAsString());
                mlKLineMasterVo.setF12(arr.get(2).getAsString());
                mlKLineMasterVo.setF14(arr.get(1).getAsString());
                mlKLineMasterVo.setF23(String.valueOf(new BigDecimal(arr.get(46).getAsString()).multiply(new BigDecimal(100))));
                mlKLineMasterVo.setSymbol(arr.get(2).getAsString());
                mlKLineMasterVo.setUpper_limit(arr.get(47).getAsString());
                mlKLineMasterVo.setLower_limit(arr.get(48).getAsString());
                List<SellPanKouVo> sellPanKouVos = new ArrayList<>();
                // 卖一到卖五的数据下标
                int[] priceIdx = {19, 21, 23, 25, 27};
                int[] volIdx = {20, 22, 24, 26, 28};
                //买一到卖五的数据下标
                int[] buyPriceIdx = {9, 11, 13, 15, 17};
                int[] buypVolIdx = {10, 12, 14, 16, 18};
                for (int i = 0; i < 5; i++) {
                    SellPanKouVo sellPanKouVo = new SellPanKouVo();
                    String price = ((arr.size()>(priceIdx[i]))?arr.get((priceIdx[i])).getAsString():"");
                    String vol = ((arr.size()>(volIdx[i]))?arr.get((volIdx[i])).getAsString():"");
                    BigDecimal add = new BigDecimal(1).add(BigDecimal.valueOf(i));
                    Integer integer = Integer.valueOf(String.valueOf(add));
                    sellPanKouVo.setValue("卖" + NumberChineseFormatter.format(integer,false));
                    sellPanKouVo.setAskprice(new BigDecimal(price));
                    sellPanKouVo.setAskvolume(new BigDecimal(vol));
                    sellPanKouVos.add(sellPanKouVo);
                }

                List<BuyPanKouVo> buyPanKouVos = new ArrayList<>();
                for (int i = 0; i < 5; i++) {
                    BuyPanKouVo buyPanKouVo = new BuyPanKouVo();
                    String buyPrice = ((arr.size()>(buyPriceIdx[i]))?arr.get((buyPriceIdx[i])).getAsString():"");
                    String buyVol = ((arr.size()>(buypVolIdx[i]))?arr.get((buypVolIdx[i])).getAsString():"");
                    BigDecimal add = new BigDecimal(1).add(BigDecimal.valueOf(i));
                    Integer integer = Integer.valueOf(String.valueOf(add));
                    buyPanKouVo.setValue("买" + NumberChineseFormatter.format(integer,false));
                    buyPanKouVo.setBidprice(new BigDecimal(buyPrice));
                    buyPanKouVo.setBidvolume(new BigDecimal(buyVol));
                    buyPanKouVos.add(buyPanKouVo);
                }
                mlKLineMasterVo.setSellPanKouVos(sellPanKouVos);
                mlKLineMasterVo.setBuyPanKouVos(buyPanKouVos);
                //市盈率52
                //市净率46
                mlKLineMasters.add(mlKLineMasterVo);
            }
            // 防止频繁请求被风控
            Thread.sleep(600);
        }
        return mlKLineMasters;
    }
}
